package math.base;

/**
 * @author Saga
 *
 */
public class Coord2d {
    public Coord2d() {
        this.x = 0.0;
        this.y = 0.0;
    }

    public Coord2d(final double _x, final double _y) {
        this.x = _x;
        this.y = _y;
    }

    //setget
    public final void init(final double _x, final double _y) {
        this.x = _x;
        this.y = _y;
    }

    public final void setX(final double _x) {
        this.x = _x;
    }

    public final double getX() {
        return this.x;
    }

    public final void setY(final double _y) {
        this.y = _y;
    }

    public final double getY() {
        return this.y;
    }

    public final void setCoord(final int _id, final double _val) {
        switch (_id) {
        case 0:
            this.x = _val;
            return;

        case 1:
            this.y = _val;
            return;

        default:
            throw new IndexOutOfBoundsException("");
        }
    }

    public final double getCoord(final int _id) {
        switch (_id) {
        case 0:
            return this.x;

        case 1:
            return this.y;

        default:
            throw new IndexOutOfBoundsException("");
        }
    }

    //equal
    public final boolean isEqual(final Coord2d _coord, final double _tol) {
        return Math.abs(this.x - _coord.x) <= _tol && Math.abs(this.y - _coord.y) <= _tol;
    }

    //add
    public final void add(final Coord2d _coord) {
        this.x += _coord.x;
        this.y += _coord.y;

    }

    public final Coord2d added(final Coord2d _coord) {
        return new Coord2d(this.x + _coord.x, this.y + _coord.y);
    }

    //subtract
    public final void subtract(final Coord2d _coord) {
        this.x -= _coord.x;
        this.y -= _coord.y;
    }

    public final Coord2d subtracted(final Coord2d _coord) {
        return new Coord2d(this.x - _coord.x, this.y - _coord.y);
    }

    //reverse
    public final void reverse() {
        this.x = -this.x;
        this.y = -this.y;
    }

    public final Coord2d reversed() {
        return new Coord2d(-this.x, -this.y);
    }

    //multiply
    public final void multiply(final double _scalar) {
        this.x *= _scalar;
        this.y *= _scalar;
    }

    public final Coord2d multiplied(final double _scalar) {
        return new Coord2d(this.x * _scalar, this.y * _scalar);
    }

    public final void multiply(final Coord2d _coord) {
        this.x *= _coord.x;
        this.y *= _coord.y;
    }

    public final Coord2d multiplied(final Coord2d _coord) {
        return new Coord2d(this.x * _coord.x, this.y * _coord.y);
    }

    public final void multiply(final Matrix2d _mat) {
        final double tempX = this.x * _mat.getCoord(0, 0) + this.y * _mat.getCoord(1, 0);
        this.y = this.x * _mat.getCoord(0, 1) + this.y * _mat.getCoord(1, 1);
        this.x = tempX;
    }

    public final Coord2d multiplied(final Matrix2d _mat) {
        return new Coord2d(this.x * _mat.getCoord(0, 0) + this.y * _mat.getCoord(1, 0),
                this.x * _mat.getCoord(0, 1) + this.y * _mat.getCoord(1, 1));
    }

    public final void preMultiply(final Matrix2d _mat) {
        final double tempX = this.x * _mat.getCoord(0, 0) + this.y * _mat.getCoord(0, 1);
        this.y = this.x * _mat.getCoord(1, 0) + this.y * _mat.getCoord(1, 1);
        this.x = tempX;
    }

    public final Coord2d preMultiplied(final Matrix2d _mat) {
        return new Coord2d(this.x * _mat.getCoord(0, 0) + this.y * _mat.getCoord(0, 1),
                this.x * _mat.getCoord(1, 0) + this.y * _mat.getCoord(1, 1));
    }

    //divide
    public final void divide(final double _denom) {
        final double scalar = 1.0 / _denom;
        this.x *= scalar;
        this.y *= scalar;
    }

    public final Coord2d divided(final double _denom) {
        final double scalar = 1.0 / _denom;
        return new Coord2d(this.x * scalar, this.y * scalar);
    }

    public final void divide(final Coord2d _coord) {
        this.x /= _coord.x;
        this.y /= _coord.y;
    }

    public final Coord2d divided(final Coord2d _coord) {
        return new Coord2d(this.x / _coord.x, this.y / _coord.y);
    }

    //product
    public final double dot(final Coord2d _coord) {
        return this.x * _coord.x + this.y * _coord.y;
    }

    public final double crossed(final Coord2d _coord) {
        return this.x * _coord.y - this.y * _coord.x;
    }

    //magnitude
    public final double calcMagnitude() {
        return Math.sqrt(this.x * this.x + this.y * this.y);
    }

    public final double calcSquareMagnitude() {
        return this.x * this.x + this.y * this.y;
    }

    //normalize
    public final void normalize() {
        final double mag = Math.sqrt(this.x * this.x + this.y * this.y);
        if (mag <= Precision.confusion) {
            throw new ArithmeticException("");
        }

        this.x /= mag;
        this.y /= mag;
    }

    public final Coord2d normalized() {
        final double mag = Math.sqrt(this.x * this.x + this.y * this.y);
        if (mag <= Precision.confusion) {
            throw new ArithmeticException("");
        }

        return new Coord2d(this.x / mag, this.y / mag);
    }

    @Override
    public Coord2d clone() {
        return new Coord2d(this.x, this.y);
    }

    private double x;
    private double y;
}
